import math

from scipy.spatial import distance
import numpy as np
import matplotlib.pyplot as plt
import datetime


class TWVRPAssignmentNew:
    # 初始化
    def __init__(self, job_list, transport_cost_matrix,
                 route_sequence, company, vehicle_load,
                 first_date, on_work_hour, off_work_hour):
        # 任务信息
        self._job_list = job_list
        # 交通时间信息
        self._transport_cost_matrix = transport_cost_matrix
        # 工作安排顺序信息
        self._route_sequence = route_sequence.tolist()
        # 任务实体类
        self._job_entity_list = []
        # 起点信息
        self._company = company
        # 最大载荷
        self._vehicle_load = vehicle_load
        # 整个排产任务的起点时间
        self._first_date = first_date
        # 上班时间
        self._on_work_hour = on_work_hour
        # 下班时间
        self._off_work_hour = off_work_hour

    # 安排一个工作
    def eachJobAssign(self, this_job_id, prev_job_id):
        # 当前任务的名称和时间
        this_job_name = self._job_list[this_job_id]['job_name']
        this_job_start_time = self._job_list[this_job_id]['start_time']
        this_job_end_time = self._job_list[this_job_id]['end_time']
        this_job_class = self._job_list[this_job_id]['job_class']
        # 当前任务时间开销
        this_job_work_cost = self._job_list[this_job_id]['work_cost']
        # 当前任务消耗零件数量
        this_job_part_cost = self._job_list[this_job_id]['part_cost']
        # 当前预约开始时间
        this_job_can_start_time = self._first_date
        # 如果是2类任务就是要按照约定时间来，如果不是则可开始时间为0，即随时都可以，取决于上次任务结束时间
        if self._job_list[this_job_id]['job_class'] == 2:
            this_job_can_start_time = self._job_list[this_job_id]['start_time']
        else:
            this_job_can_start_time = self._first_date
        # 先查出前置任务的id和时间，如果是None则表示没有前置任务
        prev_job_end_time = self._first_date
        # prev_job_id不为空，上个节点的下个节点不为公司，所以是从其他任务地点出发
        if prev_job_id != None and self._job_entity_list[-1]['if_next_is_company'] == 'N':
            # 获取前序任务，判断上个任务结束后是否去了公司补充零件，如果没去就正常走
            prev_job_entity = self._job_entity_list[-1].copy()
            # 获取任务名称
            prev_job_name = prev_job_entity['job_name']
            # 获取上一个任务的结束时间
            prev_job_end_time = prev_job_entity['now_work_end_time']
            # 获取转移开始时间
            prev_to_now_work_trans_start_time = prev_job_end_time
            prev_to_now_work_trans_end_time = self.dateAdd(prev_to_now_work_trans_start_time,
                                                           self._transport_cost_matrix[prev_job_id][this_job_id])
            now_work_start_time = self.getMaxDate(prev_to_now_work_trans_end_time, this_job_can_start_time)
            # 当前任务结束时间为开始时间加上耗时
            now_work_end_time = self.dateAdd(now_work_start_time, this_job_work_cost)
            # 从这里开始，三个if全部一样，
            # 从公司出发按照最大载荷减去当前消耗
            now_vehicle_load = self._vehicle_load - this_job_part_cost
            # 如果消耗完零件，需要回公司补充
            if_next_is_company = 'Y'
            # 从任务地点出发，所以中序节点必然不是公司
            if_prev_is_company = 'N'
            # 判断是否要跨天，完成时是否下班，加上运输时间是否下班，后一个任务是否在后一天
            if_cross_day = self.ifCrossDay(this_job_id, now_work_start_time, now_work_end_time)
            # 如果本任务的完成时间是下班时间，下个节点也是公司
            if now_vehicle_load <= 0 or if_cross_day == 'Y':
                if_next_is_company = 'Y'
                # 如果下个节点是公司，则计算now_to_next_trans_start_time
                now_to_next_trans_start_time = now_work_end_time
                now_to_next_trans_end_time = self.dateAdd(now_to_next_trans_start_time,
                                                          self._transport_cost_matrix[this_job_id][-1])
            else:
                if_next_is_company = 'N'
                # 如果下个节点不是公司，就是正常的走，就全部是now_work_end_time
                now_to_next_trans_start_time = now_work_end_time
                now_to_next_trans_end_time = now_to_next_trans_start_time

        # 如果有前序任务就是从前序任务出发
        else:
            # prev_job_id为空表示第一天
            if prev_job_id == None:
                # 获取前序任务
                prev_job_name = '公司'
                # 获取上一个任务的结束时间
                prev_job_end_time = self._first_date
                # 获取上一个是否跨天，由于是第一个所以必然按跨天计算
                temp_if_cross_day = 'Y'
                # 获取转移开始时间,如果是跨天就从第二天上班时间开始
                if temp_if_cross_day == 'Y':
                    # 第一天不用加
                    # temp_time_string = self.dateAdd(prev_job_end_time, 24)
                    temp_time = datetime.datetime.strptime(prev_job_end_time, "%Y-%m-%d %H:%M:%S")
                    on_work_time = datetime.datetime(temp_time.year, temp_time.month,
                                                     temp_time.day, self._on_work_hour, 0, 0)
                    prev_to_now_work_trans_start_time = datetime.datetime.strftime(on_work_time, "%Y-%m-%d %H:%M:%S")
                else:
                    # 永远不会运行
                    # prev_to_now_work_trans_start_time = prev_job_end_time
                    pass
                # 直接从公司出发，计算路程
                prev_to_now_work_trans_end_time = self.dateAdd(prev_to_now_work_trans_start_time,
                                                               self._transport_cost_matrix[-1][this_job_id])
                now_work_start_time = self.getMaxDate(prev_to_now_work_trans_end_time, this_job_can_start_time)
                now_work_end_time = self.dateAdd(now_work_start_time, this_job_work_cost)
            else:
                # 获取前序任务
                prev_job_entity = self._job_entity_list[-1].copy()
                prev_job_name = prev_job_entity['job_name']
                # 获取上一个任务的结束时间
                prev_job_end_time = prev_job_entity['now_work_end_time']
                # 获取上一个是否跨天
                temp_if_cross_day = prev_job_entity['if_cross_day']
                # 获取转移开始时间,如果是跨天就从第二天上班时间开始
                if temp_if_cross_day == 'Y':
                    temp_time_string = self.dateAdd(prev_job_end_time, 24)
                    temp_time = datetime.datetime.strptime(temp_time_string, "%Y-%m-%d %H:%M:%S")
                    on_work_time = datetime.datetime(temp_time.year, temp_time.month,
                                                     temp_time.day, self._on_work_hour, 0, 0)
                    prev_to_now_work_trans_start_time = datetime.datetime.strftime(on_work_time, "%Y-%m-%d %H:%M:%S")
                else:
                    prev_to_now_work_trans_start_time = prev_job_end_time
                # 计算从开始转移到中序（公司）节点，再从公司到本任务节点的时间
                prev_to_now_work_trans_end_time = self.dateAdd(prev_to_now_work_trans_start_time, (
                        self._transport_cost_matrix[prev_job_id][-1] + self._transport_cost_matrix[-1][
                    this_job_id]))
                now_work_start_time = self.getMaxDate(prev_to_now_work_trans_end_time, this_job_can_start_time)
                # 当前任务结束时间为开始时间加上耗时
                now_work_end_time = self.dateAdd(now_work_start_time, this_job_work_cost)

            # 从这里开始，三个if全部一样，
            # 从公司出发按照最大载荷减去当前消耗
            now_vehicle_load = self._vehicle_load - this_job_part_cost
            # 如果消耗完零件，需要回公司补充
            if_next_is_company = 'Y'
            # 从公司出发，所以中序节点必是公司
            if_prev_is_company = 'Y'
            # 判断是否要跨天，完成时是否下班，加上运输时间是否下班，后一个任务是否在后一天
            if_cross_day = self.ifCrossDay(this_job_id, now_work_start_time, now_work_end_time)
            # 如果本任务的完成时间是下班时间，下个节点也是公司
            if now_vehicle_load <= 0 or if_cross_day == 'Y':
                if_next_is_company = 'Y'
                # 如果下个节点是公司，则计算now_to_next_trans_start_time
                now_to_next_trans_start_time = now_work_end_time
                now_to_next_trans_end_time = self.dateAdd(now_to_next_trans_start_time,
                                                          self._transport_cost_matrix[this_job_id][-1])
            else:
                if_next_is_company = 'N'
                # 如果下个节点不是公司，就是正常的走，就全部是now_work_end_time
                now_to_next_trans_start_time = now_work_end_time
                now_to_next_trans_end_time = now_to_next_trans_start_time

        # 拼接对象
        this_job_entity = {
            # 基本信息
            'job_id': this_job_id,
            'job_class': this_job_class,
            'job_name': this_job_name,
            'prev_job_id': prev_job_id,
            'prev_job_name': prev_job_name,
            'work_cost': this_job_work_cost,
            # 与时间相关，用于计算路上开销
            # 前序节点到当前节点路上时间
            'prev_to_now_work_trans_start_time': prev_to_now_work_trans_start_time,
            'prev_to_now_work_trans_end_time': prev_to_now_work_trans_end_time,
            # 当前节点到后续节点路上时间，主要是看是不是去公司
            'now_to_next_trans_start_time': now_to_next_trans_start_time,
            'now_to_next_trans_end_time': now_to_next_trans_end_time,
            # 是否跨天，用于判断第二天是从哪里出发
            'if_cross_day': if_cross_day,
            # 开工时间和预约时间
            'now_work_start_time': now_work_start_time,
            'now_work_end_time': now_work_end_time,
            'start_time': this_job_start_time,
            'end_time': this_job_end_time,
            # 与位置相关，不需要计算，主要用来画图
            'lon': self._job_list[this_job_id]['lon'],
            'lat': self._job_list[this_job_id]['lat'],
            'job_location': self._job_list[this_job_id]['job_location'],
            # 与载荷相关，计算是否要回公司
            'now_vehicle_load': now_vehicle_load,
            'if_next_is_company': if_next_is_company,
            'if_prev_is_company': if_prev_is_company
        }

        return this_job_entity

    # 安排一个序列的工作
    def routeSequenceAssign(self):
        for index, value in enumerate(self._route_sequence):
            this_job_id = value
            prev_job_id = None
            if index != 0:
                prev_job_id = self._job_entity_list[index - 1]['job_id']
            else:
                prev_job_id = None
            jobEntity = self.eachJobAssign(this_job_id, prev_job_id)
            self._job_entity_list.append(jobEntity)

    # 画甘特图
    def drawGantt(self):
        MColor = ['red', 'blue', 'yellow', 'orange', 'green', 'moccasin', 'purple',
                  'pink', 'navajowhite', 'Thistle', 'Magenta', 'SlateBlue', 'RoyalBlue',
                  'Aqua', 'floralwhite', 'ghostwhite', 'goldenrod', 'mediumslateblue',
                  'navajowhite', 'navy', 'sandybrown']
        fig = plt.figure(figsize=(15, 6), dpi=70)
        # 横众轴显示字体为‘仿宋’的中文标签
        plt.rcParams['font.sans-serif'] = ['FangSong']
        plt.rcParams['axes.unicode_minus'] = False
        for index, each_job in enumerate(self._job_entity_list):
            job_id = each_job['job_id']
            job_name = each_job['job_name']
            prev_job_id = each_job['prev_job_id'],
            prev_job_name = each_job['prev_job_name']
            if_prev_is_company = each_job['if_prev_is_company']
            if_cross_day = each_job['if_cross_day']
            # 计算交通开销
            transport_cost = 0
            transport_cost_text = 'abc'
            transport_company_cost = 0
            transport_company_cost_text = 'ABC'
            # 如果上个节点是公司，则计算从开始转移到中序（公司）节点，再从公司到本任务节点的时间
            if if_prev_is_company == 'N':
                transport_cost = self.dateSub(each_job['prev_to_now_work_trans_end_time'],
                                              each_job['prev_to_now_work_trans_start_time'])
                transport_cost_text = prev_job_name + '\n' + job_name
            else:
                transport_cost = self.dateSub(each_job['prev_to_now_work_trans_end_time'],
                                              each_job['prev_to_now_work_trans_start_time'])
                transport_cost_text = prev_job_name + '-公司' + '\n' + '公司-' + job_name
            # 如果当前任务要跨天，则要回去公司，画回去公司的距离
            if if_cross_day == 'Y':
                transport_company_cost = self.dateSub(each_job['now_to_next_trans_end_time'],
                                                      each_job['now_to_next_trans_start_time'])
                transport_company_cost_text = job_name + '\n' + '-公司'
            else:
                transport_company_cost = 0
                transport_company_cost_text = '-'
            # 计算零点即first_date开始那天的0点
            zero_date = datetime.datetime.strptime(self._first_date, "%Y-%m-%d %H:%M:%S")
            new_zero_date = datetime.datetime(zero_date.year, zero_date.month, zero_date.day, 0, 0, 0)
            new_zero_date_string = datetime.datetime.strftime(new_zero_date, "%Y-%m-%d %H:%M:%S")
            # 计算零点和first_date之间的差
            first_zero_date_gap = self.dateSub(self._first_date, new_zero_date_string)
            # 画交通时间开销，先计算起始位置
            # 如果前序节点不是公司就是正常颜色，不然画篮筐
            transport_cost_left = self.dateSub(each_job['prev_to_now_work_trans_start_time'],
                                               self._first_date) + first_zero_date_gap
            if if_prev_is_company == 'N':
                plt.barh(job_name, width=transport_cost,
                         height=0.8,
                         color='white',
                         edgecolor='red',
                         left=transport_cost_left)
            else:
                plt.barh(job_name, width=transport_cost,
                         height=0.8,
                         color='white',
                         edgecolor='blue',
                         left=transport_cost_left)
            # 画工作开销，先计算起始位置
            work_cost_left = self.dateSub(each_job['now_work_start_time'], self._first_date) + first_zero_date_gap
            plt.barh(job_name, width=each_job['work_cost'],
                     height=0.8,
                     color=MColor[job_id],
                     edgecolor='black',
                     left=work_cost_left)
            # 画回公司开销，先计算起始位置,如果是0则不画图
            if transport_company_cost != 0:
                transport_company_cost_left = self.dateSub(each_job['now_to_next_trans_start_time'],
                                                           self._first_date) + first_zero_date_gap
                plt.barh(job_name, width=transport_company_cost,
                         height=0.8,
                         color='white',
                         edgecolor='green',
                         left=transport_company_cost_left)
            else:
                pass
            # 交通开销表标明文字，先计算起始位置
            # transport_cost_text_x = transport_cost_left + (transport_cost / 2 - 0.4)
            # plt.text(x=transport_cost_text_x,
            #          y=index - 0.2,
            #          color='black',
            #          weight='bold',
            #          s=transport_cost_text,
            #          size=8, fontproperties='SimSun')
            # 工作开销标明文字，先计算起始位置
            work_cost_text_x = transport_cost_left - 6
            plt.text(x=work_cost_text_x,
                     y=index - 0.1,
                     color='black',
                     weight='bold',
                     s=job_name,
                     size=12, fontproperties='SimSun')
            # # 画回公司开销，先计算起始位置
            # transport_company_cost_text_x = transport_company_cost_left + (transport_company_cost / 2 - 0.4)
            # plt.text(x=transport_company_cost_text_x,
            #          y=index - 0.2,
            #          color='black',
            #          weight='bold',
            #          s=transport_company_cost_text,
            #          size=8, fontproperties='SimSun')

        plt.ylabel("维修任务", size=20, fontproperties='SimSun')
        plt.xlabel("工作小时", size=20, fontproperties='SimSun')
        # 通线时间
        total_hour = self.getSequenceCostTotalTime()
        # 坐标从0开始
        plt.xlim([0, math.ceil(total_hour) + first_zero_date_gap + 2])
        # 坐标轴设置
        plt.tick_params(labelsize=20)
        plt.tick_params(direction='in')
        plt.title('通线工时:' + str(round(total_hour, 2)))
        plt.show()

    # 画位置图
    def drawPlot(self):
        plt.rcParams['font.sans-serif'] = ['FangSong']
        plt.rcParams['axes.unicode_minus'] = False
        # 画出标出公司标签和位置
        plt.annotate(self._company['company_name'], (self._company['lon'], self._company['lat']))
        # 在标出所有节点的位置
        point_location_x = []
        point_location_y = []
        for i, v in enumerate(self._route_sequence):
            x = self._job_list[v]['lon']
            y = self._job_list[v]['lat']
            label = self._job_list[v]['job_name']
            point_location_x.append(x)
            point_location_y.append(y)
            plt.annotate(label, (x, y))
        plt.scatter(point_location_x, point_location_y, c='y')

        # 再画各个任务顺序和任务地点
        for index, value in enumerate(self._job_entity_list):
            # 原则是画到达自己的线，只有一个例外，如果下个节点是公司，则添加一条到公司的线
            # 如果上一个节点从公司出发，则画公司出发的线
            if value['if_prev_is_company'] == 'Y':
                plot_x_set = []
                plot_y_set = []
                # 先添加公司
                plot_x_set.append(self._company['lon'])
                plot_y_set.append(self._company['lat'])
                # 再添加自己
                x = value['lon']
                y = value['lat']
                plot_x_set.append(x)
                plot_y_set.append(y)
                label = str(index + 1) + ':公司-' + value['job_name']
                plt.annotate(label, (((x + self._company['lon']) / 2 - 0.1), ((y + self._company['lat']) / 2 - 0.1)))
                plt.plot(plot_x_set, plot_y_set, 'b')
            else:
                plot_x_set = []
                plot_y_set = []
                prev_x = self._job_entity_list[index - 1]['lon']
                prev_y = self._job_entity_list[index - 1]['lat']
                prev_job_name = self._job_entity_list[index - 1]['job_name']
                plot_x_set.append(prev_x)
                plot_y_set.append(prev_y)
                x = value['lon']
                y = value['lat']
                plot_x_set.append(x)
                plot_y_set.append(y)
                label = str(index + 1) + ':' + prev_job_name + '-' + value['job_name']
                plt.annotate(label, (((x + prev_x) / 2 + 0.2), ((y + prev_y) / 2 + 0.2)))
                plt.plot(plot_x_set, plot_y_set, 'r')
            # 如果下一个节点是到达公司的（任务不一定是），则到达公司的线
            if value['if_next_is_company'] == 'Y':
                plot_x_set = []
                plot_y_set = []
                # 先添加自己
                x = value['lon']
                y = value['lat']
                plot_x_set.append(x)
                plot_y_set.append(y)
                # 再添加公司
                plot_x_set.append(self._company['lon'])
                plot_y_set.append(self._company['lat'])
                label = str(index + 1) + ':' + value['job_name'] + '-公司'
                plt.annotate(label, (((x + self._company['lon']) / 2 + 0.1), ((y + self._company['lat']) / 2 + 0.1)))
                plt.plot(plot_x_set, plot_y_set, 'g')
            else:
                pass

        total_distance = self.getTotalDistance()
        plt.title('总距离' + str(round(total_distance, 2)))
        plt.show()

    # 判断误期了几个任务，并返回误期的总时间
    def getDelayNum(self):
        total_delay_num = 0
        total_delay_hour = 0
        for index, value in enumerate(self._job_entity_list):
            # 只有job_class为2才判断
            if value['job_class'] == 2:
                now_work_start_time = value['now_work_start_time']
                need_end_time = value['end_time']
                delay_hour = self.dateSub(now_work_start_time, need_end_time)
                if delay_hour > 0:
                    total_delay_hour = total_delay_hour + delay_hour
                    total_delay_num = total_delay_num + 1
                else:
                    pass
            else:
                pass
        return total_delay_num, total_delay_hour

    # 获取通线时间(即全部任务完成的时间)
    def getSequenceCostTotalTime(self):
        max_date = self._job_entity_list[-1]['now_work_end_time']
        totalHour = self.dateSub(max_date, self._first_date)
        return totalHour

    # 获取通线距离(即全部任务完成的距离)
    def getTotalDistance(self):
        total_distance = 0.0
        # 再画各个任务顺序和任务地点
        for index, value in enumerate(self._job_entity_list):
            # 原则是计算到达自己的线的长度，只有一个例外，如果下个节点是公司，则添加一条到公司的线
            # 如果上一个节点从公司出发，则计算公司出发的线的长度
            if value['if_prev_is_company'] == 'Y':
                # 公司
                company_x = self._company['lon']
                company_y = self._company['lat']
                # 自己
                x = value['lon']
                y = value['lat']
                mdistance = distance.cdist([[company_x, company_y]], [[x, y]], 'euclidean')
                total_distance = total_distance + mdistance[0][0]
            else:
                # 前一个任务点
                prev_x = self._job_entity_list[index - 1]['lon']
                prev_y = self._job_entity_list[index - 1]['lat']
                # 后一个任务点
                x = value['lon']
                y = value['lat']
                mdistance = distance.cdist([[prev_x, prev_y]], [[x, y]], 'euclidean')
                total_distance = total_distance + mdistance[0][0]
            # 如果下一个节点是到达公司的（任务不一定是），则到达公司的线
            if value['if_next_is_company'] == 'Y':
                # 自己
                x = value['lon']
                y = value['lat']
                # 公司
                company_x = self._company['lon']
                company_y = self._company['lat']
                mdistance = distance.cdist([[x, y]], [[company_x, company_y]], 'euclidean')
                total_distance = total_distance + mdistance[0][0]
            else:
                pass

        return total_distance

    # 日期相加
    def dateAdd(self, in_date_string, interval_hour):
        temp_date = datetime.datetime.strptime(in_date_string, "%Y-%m-%d %H:%M:%S")
        out_date_string = (temp_date + datetime.timedelta(hours=interval_hour)).strftime("%Y-%m-%d %H:%M:%S")
        return out_date_string

    # 日期相减
    def dateSub(self, in_date_string1, in_date_string2):
        temp_date1 = datetime.datetime.strptime(in_date_string1, "%Y-%m-%d %H:%M:%S")
        temp_date2 = datetime.datetime.strptime(in_date_string2, "%Y-%m-%d %H:%M:%S")
        intervals = temp_date1 - temp_date2
        interval_hour = (intervals.days * 24) + (intervals.seconds / 3600)
        return interval_hour

    # 返回两者间大的日期
    def getMaxDate(self, in_date_string1, in_date_string2):
        temp_date1 = datetime.datetime.strptime(in_date_string1, "%Y-%m-%d %H:%M:%S")
        temp_date2 = datetime.datetime.strptime(in_date_string2, "%Y-%m-%d %H:%M:%S")
        if temp_date1 >= temp_date2:
            return temp_date1.strftime("%Y-%m-%d %H:%M:%S")
        else:
            return temp_date2.strftime("%Y-%m-%d %H:%M:%S")
        pass

    # 获取今天的下班时间
    def getTodayOffWorkTime(self, in_date_string):
        temp_date = datetime.datetime.strptime(in_date_string, "%Y-%m-%d %H:%M:%S")
        off_work_time = datetime.datetime(temp_date.year, temp_date.month,
                                          temp_date.day, self._off_work_hour, 0, 0)
        return datetime.datetime.strftime(off_work_time, "%Y-%m-%d %H:%M:%S")

    # 是否跨天
    def ifCrossDay(self, this_job_id, now_work_start_time, now_work_end_time):
        # 判断是否要跨天，完成时是否下班，加上运输时间是否下班，后一个任务是否在后一天
        if_cross_day = 'Y'
        next_job_location = self._route_sequence.index(this_job_id) + 1
        if next_job_location >= len(self._route_sequence):
            # 表明是最后一个
            if_cross_day = 'N'
        else:
            next_job_id = self._route_sequence[next_job_location]
            next_job_start_time = self._job_list[next_job_id]['start_time']
            # 如果next_job_start_time不为空则表示是job_class为2
            if next_job_start_time != None:
                # 本任务结束加上到下个任务地点的时间
                this_job_max_time = self.dateAdd(now_work_end_time,
                                                 self._transport_cost_matrix[this_job_id][next_job_id])
                this_job_max_date = datetime.datetime.strptime(this_job_max_time, "%Y-%m-%d %H:%M:%S")
                # 本人任务的起始时间
                this_job_start_date = datetime.datetime.strptime(now_work_start_time, "%Y-%m-%d %H:%M:%S")
                # 下个任务的起始时间
                next_job_start_date = datetime.datetime.strptime(next_job_start_time, "%Y-%m-%d %H:%M:%S")
                if (this_job_max_date.hour >= self._off_work_hour
                    or this_job_max_date.day > this_job_start_date.day) \
                        or next_job_start_date.day > this_job_max_date.day:
                    if_cross_day = 'Y'
                else:
                    if_cross_day = 'N'
            # 如果next_job_start_time为空则表示是job_class为1，只需要判断是否下班即可
            else:
                # 本任务结束加上到下个任务地点的时间
                this_job_max_time = self.dateAdd(now_work_end_time,
                                                 self._transport_cost_matrix[this_job_id][next_job_id])
                this_job_max_date = datetime.datetime.strptime(this_job_max_time, "%Y-%m-%d %H:%M:%S")
                # 本人任务的起始时间
                this_job_start_date = datetime.datetime.strptime(now_work_start_time, "%Y-%m-%d %H:%M:%S")
                if (this_job_max_date.hour >= self._off_work_hour
                        or this_job_max_date.day > this_job_start_date.day):
                    if_cross_day = 'Y'
                else:
                    if_cross_day = 'N'
        return if_cross_day


# 建立数据
def create_data():
    # 任务信息,wokr_cost时间开销，单位小时；job_class任务类别，
    # 1为优先任务，2为时间窗任务
    job_list = [
        {'job_id': 0, 'job_name': '1号任务',
         'job_location': 'A地', 'lon': 3, "lat": 5.5,
         'work_cost': 2.5, 'part_cost': 1,
         'job_class': 2, 'start_time': "2022-10-20 08:30:00",
         'end_time': "2022-10-20 18:30:00"},
        {'job_id': 1, 'job_name': '2号任务',
         'job_location': 'B地', 'lon': 8, "lat": 7,
         'work_cost': 2.5, 'part_cost': 1,
         'job_class': 2, 'start_time': "2022-10-20 08:30:00",
         'end_time': "2022-10-20 18:30:00"},
        {'job_id': 2, 'job_name': '3号任务',
         'job_location': 'C地', 'lon': 2, "lat": 2,
         'work_cost': 2.5, 'part_cost': 1,
         'job_class': 2, 'start_time': "2022-10-21 08:30:00",
         'end_time': "2022-10-21 18:30:00"},
        {'job_id': 3, 'job_name': '4号任务',
         'job_location': 'D地', 'lon': 1, "lat": 4,
         'work_cost': 2.5, 'part_cost': 1,
         'job_class': 2, 'start_time': "2022-10-21 08:30:00",
         'end_time': "2022-10-21 18:30:00"},
        {'job_id': 4, 'job_name': '5号任务',
         'job_location': 'E地', 'lon': 9, "lat": 3,
         'work_cost': 2.5, 'part_cost': 1,
         'job_class': 2, 'start_time': "2022-10-22 08:30:00",
         'end_time': "2022-10-22 15:30:00"},
        {'job_id': 5, 'job_name': '6号任务',
         'job_location': 'F地', 'lon': 7, "lat": 2,
         'work_cost': 1, 'part_cost': 1,
         'job_class': 1, 'start_time': None,
         'end_time': None},
        {'job_id': 6, 'job_name': '7号任务',
         'job_location': 'G地', 'lon': 5, "lat": 3,
         'work_cost': 1.5, 'part_cost': 1,
         'job_class': 1, 'start_time': None,
         'end_time': None},
    ]
    company_info = {
        'company_name': '公司', 'lon': 4, "lat": 4
    }
    # 固定生成8*8的交通开销矩阵，默认第一行第二列为为第一个地点到第二个地点的时间开销，
    # 最后一行为公司到各个地点的开销，这样保证序号都是对的上，每行最后一列表示该点到公司的开销
    transport_cost_matrix = []
    points_list = []
    for index, value in enumerate(job_list):
        points_list.append((value['lon'], value['lat']))
    # 最后还要加上公司
    points_list.append((company_info['lon'], company_info['lat']))
    transport_cost_matrix = distance.cdist(points_list, points_list, 'euclidean')
    # 由于数字太大，全部除以2,且保留一位小数，比如2.2表示需要2.2小时即2小时12分
    transport_cost_matrix = np.around(transport_cost_matrix / 2, decimals=1)
    # 车辆载荷
    vehicle_load = 4
    # 整个任务指派的起点时间
    first_date = "2022-10-20 00:00:00"
    # 下班时间
    off_work_hour = 18
    # 上班时间
    on_work_hour = 8
    # 返回数值
    return job_list, transport_cost_matrix, company_info, vehicle_load, first_date, on_work_hour, off_work_hour


if __name__ == '__main__':
    # 构造数据集
    job_list, transport_cost_matrix, company_info, \
    vehicle_load, first_date, on_work_hour, off_work_hour = create_data()
    # 任意一个序列
    route_sequence = np.asarray([6, 5, 2, 1, 3, 0, 4])
    # route_sequence = np.asarray([0, 1, 3, 2, 6, 5, 4])
    # route_sequence = np.asarray([1, 4, 6, 0, 5, 3, 2])
    # 初始化
    twvrpAssignment = TWVRPAssignmentNew(job_list, transport_cost_matrix,
                                         route_sequence, company_info,
                                         vehicle_load, first_date,
                                         on_work_hour, off_work_hour)
    # 安排任务
    twvrpAssignment.routeSequenceAssign()
    # 打印延期任务
    total_delay_num, total_delay_hour = twvrpAssignment.getDelayNum()
    print(total_delay_num, total_delay_hour)
    # 画甘特图
    twvrpAssignment.drawGantt()
    # 画距离图
    twvrpAssignment.drawPlot()
    # 通过
    pass
